//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Collections;
using System.IO;
using System.Security;
using CommunityServer.Components;
using CommunityServer.Galleries.Components;
using CommunityServer.Galleries.Controls;

namespace CommunityServer.Galleries
{
	/// <summary>
	/// Manager class for the <see cref="Gallery"/> objects.  This class cannot be instanciated, it contains all static methods.
	/// </summary>
	public class Galleries
	{
		// Do not allow the class to be instanciated.
		private Galleries() { }


		#region CreateUpdateDelete
		public static int Update(Gallery g)
		{
			return UpdateGallery(g);
		}

		public static int Add(Gallery g)
		{
			return AddGallery(g);
		}

		public static void Delete(Gallery g)
		{
			DeleteGallery(g);
		}
		#endregion

		
		#region Gallery


		/// <summary>
		/// This method creates a new <see cref="Gallery"/>.  It returns the ForumID of object in the database.
		/// </summary>
		/// <param name="gallery">The <see cref="Gallery"/> object to create</param>
		/// <returns>int</returns>
		public static int AddGallery(Gallery gallery)
		{ 
			// Make sure the date is set for the gallery
			gallery.DateCreated = DateTime.Now;

			// Make sure it is clean
			gallery.Name = HtmlScrubber.Clean(gallery.Name, true, true);
			gallery.Description = HtmlScrubber.Clean(gallery.Description, true, true);

			// Censor the stuff, if enabled
			if(CSContext.Current.SiteSettings.EnableCensorship)
			{
				gallery.Name = Transforms.CensorPost(gallery.Name);
				gallery.Description = Transforms.CensorPost(gallery.Description);
			}

			// Create the gallery
			gallery.SectionID = Sections.AddSection(gallery);

			// Return the ID
			return gallery.SectionID;
		}


		/// <summary>
		/// This method updates a <see cref="Gallery"/> object.
		/// </summary>
		/// <param name="gallery">The <see cref="Gallery"/> object to update</param>
		/// <returns>int</returns>
		public static int UpdateGallery(Gallery gallery) 
		{
			// Make sure it is clean
			gallery.Name = HtmlScrubber.Clean(gallery.Name, true, true);
			gallery.Description = HtmlScrubber.Clean(gallery.Description, true, true);

			// Censor the stuff, if enabled
			if(CSContext.Current.SiteSettings.EnableCensorship)
			{
				gallery.Name = Transforms.CensorPost(gallery.Name);
				gallery.Description = Transforms.CensorPost(gallery.Description);
			}

			//Unpack the GalleryImageSettings
			/*
			gallery.SetExtendedAttribute( "ThumbnailX", gallery.Thumbnail.Width.ToString());
			gallery.SetExtendedAttribute( "ThumbnailY", gallery.Thumbnail.Height.ToString());
			gallery.SetExtendedAttribute( "ThumbnailQuality", gallery.Thumbnail.Quality.ToString());
			gallery.SetExtendedAttribute( "ThumbnailBrightness", gallery.Thumbnail.Brightness.ToString() );
			gallery.SetExtendedAttribute( "ThumbnailWatermarkType", gallery.Thumbnail.WatermarkType.ToString() );
			gallery.SetExtendedAttribute( "ThumbnailWatermarkPosition", gallery.Thumbnail.WatermarkPosition.ToString() );
			gallery.SetExtendedAttribute( "ThumbnailWatermarkText", gallery.Thumbnail.WatermarkText.ToString() );
		
			gallery.SetExtendedAttribute( "SecondaryThumbnailX", gallery.SecondaryThumbnail.Width.ToString());
			gallery.SetExtendedAttribute( "SecondaryThumbnailY", gallery.SecondaryThumbnail.Height.ToString());
			gallery.SetExtendedAttribute( "SecondaryThumbnailQuality", gallery.SecondaryThumbnail.Quality.ToString());
			gallery.SetExtendedAttribute( "SecondaryThumbnailBrightness", gallery.SecondaryThumbnail.Brightness.ToString() );
			gallery.SetExtendedAttribute( "SecondaryThumbnailWatermarkType", gallery.SecondaryThumbnail.WatermarkType.ToString() );
			gallery.SetExtendedAttribute( "SecondaryThumbnailWatermarkPosition", gallery.SecondaryThumbnail.WatermarkPosition.ToString() );
			gallery.SetExtendedAttribute( "SecondaryThumbnailWatermarkText", gallery.SecondaryThumbnail.WatermarkText.ToString() );

			gallery.SetExtendedAttribute( "PictureDetailsX", gallery.PictureDetails.Width.ToString());
			gallery.SetExtendedAttribute( "PictureDetailsY",  gallery.PictureDetails.Height.ToString());
			gallery.SetExtendedAttribute( "PictureDetailsQuality",  gallery.PictureDetails.Quality.ToString());
			gallery.SetExtendedAttribute( "PictureDetailsBrightness",  gallery.PictureDetails.Brightness.ToString() );
			gallery.SetExtendedAttribute( "PictureDetailsWatermarkType", gallery.PictureDetails.WatermarkType.ToString() );
			gallery.SetExtendedAttribute( "PictureDetailsWatermarkPosition", gallery.PictureDetails.WatermarkPosition.ToString() );
			gallery.SetExtendedAttribute( "PictureDetailsWatermarkText", gallery.PictureDetails.WatermarkText.ToString() );

			gallery.SetExtendedAttribute( "SlideshowX",  gallery.Slideshow.Width.ToString());
			gallery.SetExtendedAttribute( "SlideshowY", gallery.Slideshow.Height.ToString());
			gallery.SetExtendedAttribute( "SlideshowQuality", gallery.Slideshow.Quality.ToString());
			gallery.SetExtendedAttribute( "SlideshowBrightness", gallery.Slideshow.Brightness.ToString() );
			gallery.SetExtendedAttribute( "SlideshowWatermarkType", gallery.Slideshow.WatermarkType.ToString() );
			gallery.SetExtendedAttribute( "SlideshowWatermarkPosition", gallery.Slideshow.WatermarkPosition.ToString() );
			gallery.SetExtendedAttribute( "SlideshowWatermarkText", gallery.Slideshow.WatermarkText.ToString() );
			*/
			// Update the gallery
			return Sections.UpdateSection(gallery);
		}


		/// <summary>
		/// This method deletes a specified <see cref="Gallery"/> and all of the <see cref="GalleryImage"/> items it contains.
		/// </summary>
		/// <param name="galleryID"></param>
		public static void DeleteGallery(int galleryID)
		{
			// We first need the gallery, to do a few things
			Gallery gallery = GetGallery(galleryID, false);

			DeleteGallery(gallery);
		}

		
		/// <summary>
		/// This method deletes a specified <see cref="Gallery"/> and all of the <see cref="GalleryImage"/> items it contains.
		/// </summary>
		public static void DeleteGallery(Gallery gallery)
		{

			// Delete the gallery in the database
			Sections.DeleteSection(gallery) ;

			// Delete all remaining cache files
			try
			{
				GalleryConfiguration.Instance().CacheSettings.LegacyClearStorage(gallery.SectionID);
				GalleryConfiguration.Instance().CacheSettings.DeleteSectionFromDisk(gallery.SectionID) ;
			}
			catch(IOException e)
			{ new CSException(CSExceptionType.AccessDenied, "DeleteGallery: Permission to delete cache file denied.", e).Log(); }
			catch(SecurityException e)
			{ new CSException(CSExceptionType.AccessDenied, "DeleteGallery: Permission to delete cache file denied.", e).Log(); }
			catch { }

			// Delete the picture files
			try
			{
				GalleryConfiguration.Instance().AttachmentSettings.LegacyClearStorage(gallery.SectionID);
				GalleryConfiguration.Instance().AttachmentSettings.DeleteSectionFromDisk(gallery.SectionID);
			}
			catch(IOException e)
			{ new CSException(CSExceptionType.AccessDenied, "DeleteGallery: Permission to delete picture on filesystem denied.", e).Log(); }
			catch(SecurityException e)
			{ new CSException(CSExceptionType.AccessDenied, "DeleteGallery: Permission to delete picture on filesystem denied.", e).Log(); }
			catch { }

			// Delete the folders
			try
			{
				WebDirectory.Delete(Globals.GetSiteUrls().Locations["galleries"] + gallery.ApplicationKey) ;
			}
			catch(IOException e)
			{ new CSException(CSExceptionType.AccessDenied, "DeleteGallery: Permission to delete the folder on filesystem denied.", e).Log(); }
			catch(SecurityException e)
			{ new CSException(CSExceptionType.AccessDenied, "DeleteGallery: Permission to delete the folder on filesystem denied.", e).Log(); }
			catch { }
		}

		public static Gallery GetRandomGallery()
		{
			return GetRandomGallery(false);
		}

		public static Gallery GetRandomGallery(bool ensureHasPictures)
		{
			ArrayList galleries = GetGalleries();

			for (int i = 0; i < galleries.Count; i++)
			{
				if (((Section) galleries[i]).TotalThreads == 0)
				{
					galleries.RemoveAt(i);
					i--;
				}
			}

			Section section = Sections.GetRandomSection(galleries);
			if(section == null)
				return null;

			return section as Gallery;
		}

        public static Gallery GetGallery()
        {
			CSContext cSContext = CSContext.Current;
			string appKey = cSContext.ApplicationKey;
			if(!Globals.IsNullorEmpty(appKey))
				return Galleries.GetGallery(appKey);

			int sectionID = cSContext.SectionID;
			if(sectionID > 0)
				return Galleries.GetGallery(sectionID);

			appKey = GalleryConfiguration.Instance().DefautApplicationKey;
			if(!Globals.IsNullorEmpty(appKey))
				return Galleries.GetGallery(appKey);

			return null;
			
        }

		/// <summary>
		/// This method gets the specified <see cref="Gallery"/>
		/// </summary>
		/// <param name="galleryID">The ID of the <see cref="Gallery"/> to retrieve</param>
		/// <returns><see cref="Gallery"/></returns>
		public static Gallery GetGallery(int galleryID)
		{
			return GetGallery(galleryID, true);
		}

		/// <summary>
		/// This method gets the specified <see cref="Gallery"/>.  Allows you to specified if the data is cached.
		/// </summary>
		/// <param name="galleryID">The ID of the <see cref="Gallery"/> to retrieve</param>
		/// <param name="cacheable">Specify whether or not the data will be cached</param>
		/// <returns><see cref="Gallery"/></returns>
		public static Gallery GetGallery(int galleryID, bool cacheable)
		{
		    CSContext csContext = CSContext.Current;
			Hashtable galleries = GetGalleries(csContext, csContext.User.UserID, true, cacheable, false, true);

			// Return the gallery
			foreach(Gallery gallery in galleries.Values)
				if(gallery.SectionID == galleryID)
					return gallery;

			// If we are still here, then the gallery doesn't exist
			PermissionBase.RedirectOrExcpetion(CSExceptionType.SectionNotFound, "Gallery not found: " + galleryID);
            return null;
		}

		/// <summary>
		/// This method gets the spcified <see cref="Gallery"/>.
		/// </summary>
		/// <param name="applicationKey">The ApplicationKey of the <see cref="Gallery"/> to retrieve</param>
		/// <returns><see cref="Gallery"/></returns>
		public static Gallery GetGallery(string applicationKey)
		{
			return GetGallery(applicationKey, true);
		}

		public static bool Exists(string applicationKey)
		{
			applicationKey = applicationKey.ToLower();
			CSContext csContext = CSContext.Current;
			Hashtable galleries = GetGalleries(csContext, csContext.User.UserID, true, true, false, true);

			// Check for the gallery
			Gallery gallery = galleries[applicationKey] as Gallery;

			if(gallery != null)
				return true;
			else
				return false;
		}

		/// <summary>
		/// This method gets the specified <see cref="Gallery"/>.  Allows you to specify if the data is cached.
		/// </summary>
		/// <param name="applicationKey">The ApplicationKey of the <see cref="Gallery"/> to retrieve</param>
		/// <param name="cacheable">Specify whether or not the data will be cached</param>
		/// <returns><see cref="Gallery"/></returns>
		public static Gallery GetGallery(string applicationKey, bool cacheable)
		{
			applicationKey = applicationKey.ToLower();
		    CSContext csContext = CSContext.Current;
			Hashtable galleries = GetGalleries(csContext, csContext.User.UserID, true, cacheable, false, true);

			// Return the gallery
			Gallery gallery = galleries[applicationKey] as Gallery;

			if(gallery != null)
				return gallery;
			
			// If we are still here, then the gallery doesn't exist
			PermissionBase.RedirectOrExcpetion(CSExceptionType.ResourceNotFound, "Gallery not found: " + applicationKey);
            return null;
		}

		/// <summary>
		/// This method gets all of the <see cref="Gallery"/> objects at the current site.
		/// </summary>
		/// <returns><see cref="ArrayList"/></returns>
		public static ArrayList GetGalleries()
		{
			return GetGalleries(CSContext.Current.User.UserID, false, true, false);
		}

		/// <summary>
		/// This method gets all of the <see cref="Gallery"/> objects at the curren site.  Allows you to specify if the data is cached.
		/// </summary>
		/// <param name="cacheable">Specify whether or not the data will be cached</param>
		/// <returns>ArrayList</returns>
		public static ArrayList GetGalleries(bool cacheable, bool flush)
		{
			return GetGalleries(CSContext.Current.User.UserID, false, cacheable, flush);
		}

		/// <summary>
		/// This method gets all of the <see cref="Gallery"/> objects at the current site.  Allows you to specify the user to retrieve
		/// <see cref="Gallery"/> objects from, whether to ignore permissions, and whether to cache the data.
		/// </summary>
		/// <param name="userID">The UserID of the <see cref="User"/> to filter based on permissions</param>
		/// <param name="ignorePermissions">Specified whether not to ignore permissions.</param>
		/// <param name="cacheable">Specified whether or not to cache the data</param>
		/// <returns>ArrayList</returns>
		public static ArrayList GetGalleries(int userID, bool ignorePermissions, bool cacheable, bool flush)
		{
		    CSContext csContext = CSContext.Current;
			ArrayList galleries = new ArrayList();
			Hashtable galleriesTable;

			// Get the Albums as a hashtable
			galleriesTable = GetGalleries(csContext, userID, ignorePermissions, cacheable, flush, false);

			foreach(Gallery gallery in galleriesTable.Values)
				galleries.Add( gallery );

			galleries.Sort(new SectionSorter());

			return galleries;
		}

		public static ArrayList GetGalleriesByGroupID(int groupID, bool ignorePermissions, bool cacheable, bool flush)
		{
			return GetGalleriesByGroupID(groupID, CSContext.Current.User.UserID, ignorePermissions, cacheable, flush);
		}

		public static ArrayList GetGalleriesByGroupID(int groupID, int userID, bool ignorePermissions, bool cacheable, bool flush) 
		{
		    CSContext csContext = CSContext.Current;
			ArrayList galleries = new ArrayList();
			Hashtable forumsTable;

			// Get the ForumGroups as a hashtable
			forumsTable = GetGalleries(csContext, userID, ignorePermissions, cacheable, flush, false);

			// Convert the hashtable to an arraylist
			foreach(Gallery gallery in forumsTable.Values)
				if (gallery.GroupID == groupID)
					galleries.Add( gallery );

			// Sort the galleries
			galleries.Sort(new SectionSorter());

			return galleries;
		}

        private static readonly string galleryCacheKeyFormat = "Galleries-Site:{0}";

        public static void ResetGalleryCache()
        {
            CSCache.Remove(string.Format(galleryCacheKeyFormat,CSContext.Current.SiteSettings.SettingsID));
        }

		public static Hashtable GetGalleries(CSContext csContext, int userID, bool ignorePermissions, bool cacheable, bool flush, bool ignoreLanguageFilter)
		{
			Hashtable unfilteredGalleries = null;
			User user = CSContext.Current.User;

			string cacheKey = string.Format(galleryCacheKeyFormat, csContext.SiteSettings.SettingsID);
			string localKey = string.Format("GalleriesForUser:{0}:{1}",ignorePermissions,ignoreLanguageFilter);

			#region NoCache
#if DEBUG_NOCACHE
            cacheable = false;
#endif
			#endregion

			if(flush)
			{
				CSCache.Remove(cacheKey);
				csContext.Items[localKey] = null;
			}

			// See if this has already been requested
			unfilteredGalleries = csContext.Items[localKey] as Hashtable;
			if(unfilteredGalleries != null)
				return unfilteredGalleries;

			// Ensure it's not in the cache
			if(!cacheable)
				CSCache.Remove(cacheKey);

			// Have we already fetched for this request?
			unfilteredGalleries = CSCache.Get(cacheKey) as Hashtable;

			// Get the albums if it is not in the cache
			if(unfilteredGalleries == null)
			{
				unfilteredGalleries = GalleryDataProvider.Instance().GetGalleries(true);

				// Cache if we can
				if(cacheable)
					CSCache.Insert(cacheKey, unfilteredGalleries, 15 * CSCache.MinuteFactor);
			} 

			if (!ignoreLanguageFilter && !ignorePermissions)
				unfilteredGalleries = Sections.FilterByLanguage(unfilteredGalleries, csContext);

			// Are we ignoring permissions?
			if(ignorePermissions)
			{
				csContext.Items[localKey] = unfilteredGalleries;
				return unfilteredGalleries;
			}

			// We need to create a new hashtable
			Hashtable galleries = new Hashtable();

			// Filter the list of blogs to only show blogs this user 
			// is allowed to see
			foreach(Gallery gallery in unfilteredGalleries.Values)
			{
				// The forum is added if the user can View, Read
				if( Permissions.ValidatePermissions( gallery, Permission.View, user ))
				{
					if(gallery.IsActive || user.IsGalleryAdministrator)
						galleries.Add(gallery.ApplicationKey, gallery);
				}
			}

			// Insert into request cache
			csContext.Items[localKey] = galleries;

			return galleries;
		}

		public static int GetGalleryID(string applicationKey)
		{
			if(applicationKey == string.Empty)
				return -1;
			else
				return GetGallery(applicationKey).SectionID;
		}


		#endregion


		#region GalleryGroups

		public static Group GetGalleryGroup(int groupID, bool cacheable, bool ignorePermissions)
		{
			ArrayList galleryGroups = GetGalleryGroups(cacheable, ignorePermissions, false);
			foreach(Group fg in galleryGroups)
				if(fg.GroupID == groupID)
					return fg;
			return null;
		}

		public static ArrayList GetGalleryGroups(bool cacheable, bool ignorePermissions, bool flush)
		{
			return GetGalleryGroups(CSContext.Current.User.UserID, cacheable, ignorePermissions, flush);
		}

		public static ArrayList GetGalleryGroups(int userID, bool cacheable, bool ignorePermissions, bool flush)
		{
			ArrayList forumGroups = new ArrayList();
			Hashtable forumGroupsTable;

			// Get the ForumGroups as a hashtable
			//
			forumGroupsTable = GetGalleryGroups(cacheable, ignorePermissions, userID, flush);

			// Hide forum groups based on the user's cookie
			//
			forumGroupsTable = Groups.HideGroups(forumGroupsTable);

			// Convert the hashtable to an arraylist
			//
			foreach(Group fg in forumGroupsTable.Values)
				forumGroups.Add( fg );

			// Sort the forum groups
			//
			forumGroups.Sort();

			return forumGroups;
		}

		private static Hashtable GetGalleryGroups(bool cacheable, bool ignorePermissions, int userID, bool flush) 
		{
			CSContext cSContext = CSContext.Current;
			int settingsID = cSContext.SiteSettings.SettingsID;
			string cacheKey = string.Format("AllGalleryGroups-{0}",settingsID);
			Hashtable unfilteredForumGroups;
			Hashtable forumGroups;

			if(flush)
			{
				cSContext[cacheKey] = null;
				CSCache.Remove(cacheKey);
			}

			// Evict item from cache if not cacheable
			//
			if (!cacheable)
				CSCache.Remove(cacheKey);

			// Get the raw forum groups
			//
			unfilteredForumGroups = CSCache.Get(cacheKey) as Hashtable;
			if(unfilteredForumGroups == null) 
			{
				unfilteredForumGroups = CommonDataProvider.Instance().GetGroups(ApplicationType.Gallery, false);

				if (cacheable)
					CSCache.Insert(cacheKey,unfilteredForumGroups,CSCache.HourFactor);
			} 

			// Are we ignoring permissions?
			//
			if(ignorePermissions)
				return unfilteredForumGroups;

			// We need to create a new hashtable
			//
			forumGroups = new Hashtable();

			// Filter the list of forum groups to only show forums groups
			// this user is allowed to see, i.e. if all the forums in this
			// group are private and the user is not allowed to see them
			//
			foreach (Group f in unfilteredForumGroups.Values) 
			{
				// Get the associated forums
				//
				if (!cacheable) 
					forumGroups.Add(f.GroupID, f);
				else if (GetGalleriesByGroupID(f.GroupID, userID, ignorePermissions, cacheable, false).Count > 0)
					forumGroups.Add(f.GroupID, f);
			}

			return forumGroups;
		}

		#endregion


	}
}
